package com.eastfair.home.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.constant.BusinessInnerMsgTemplate;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.context.StaticContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.home.dao.WorkOvertimeAuditMapper;
import com.eastfair.home.dto.WorkOvertimeAuditDTO;
import com.eastfair.home.entity.WorkOvertimeAudit;
import com.eastfair.home.enumeration.WorkOvertimeAuditAuditStatusEnum;
import com.eastfair.home.exceptioncode.HomeExceptionCode;
import com.eastfair.home.service.HomeServiceProviderService;
import com.eastfair.home.service.HomeServiceProviderSpaceService;
import com.eastfair.home.service.HomeWorkOvertimeService;
import com.eastfair.home.service.WorkOvertimeAuditService;
import com.eastfair.home.vo.WorkOvertimeAuditVO;
import com.eastfair.messagecenter.util.SendMsgUtil;
import com.eastfair.venueservice.consts.CommonConstants;
import com.eastfair.venueservice.dto.WorkOvertimeDTO;
import com.eastfair.venueservice.enumeration.ServiceProviderTypeEnum;
import com.eastfair.venueservice.enumeration.WorkOvertimeWorkOvertimeTypeEnum;
import com.eastfair.venueservice.vo.ServiceProviderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 加班审核
 * </p>
 *
 * @author dq
 * @date 2022-10-19
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class WorkOvertimeAuditServiceImpl extends SuperServiceImpl<WorkOvertimeAuditMapper, WorkOvertimeAudit> implements WorkOvertimeAuditService {

    @Resource
    private HomeWorkOvertimeService homeWorkOvertimeService;

    @Resource
    private HomeServiceProviderService homeServiceProviderService;

    @Resource
    private HomeServiceProviderSpaceService homeServiceProviderSpaceService;

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private SendMsgUtil sendMsgUtil;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<WorkOvertimeAudit> modelList) {
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(WorkOvertimeAudit model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        if (model.getAuditStatus() == null) {
            model.setAuditStatus(WorkOvertimeAuditAuditStatusEnum.SUBMIT);
        }
        return R.successDef();
    }

    @Override
    public Page<WorkOvertimeAuditVO> listWorkOvertimeAuditVO(PageParams<WorkOvertimeAuditDTO> pageParams) {
        log.info("listWorkOvertimeAuditVO - 分页查询加班审核列表VO, pageParams={}", pageParams);
        Page<WorkOvertimeAuditVO> voPage = new Page<>();
        Page<WorkOvertimeAudit> page = listWorkOvertimeAudit(pageParams);
        BeanUtil.copyProperties(page, voPage);
        List<WorkOvertimeAudit> list = page.getRecords();
        if (list == null || list.isEmpty()) {
            return voPage;
        }
        List<WorkOvertimeAuditVO> voList = list
                .stream()
                .map(workOvertimeAudit -> BeanUtil.toBean(workOvertimeAudit, WorkOvertimeAuditVO.class))
                .collect(Collectors.toList());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    public Page<WorkOvertimeAudit> listWorkOvertimeAudit(PageParams<WorkOvertimeAuditDTO> pageParams) {
        WorkOvertimeAuditDTO model = pageParams.getModel();
        Page<WorkOvertimeAudit> pageParam = pageParams.buildPage();
        // 查询主场在该展会下的展馆编码
        List<String> spaceCodeList
                = homeServiceProviderSpaceService.listSpaceCodesByServiceProviderId(model.getHomeCourtId(), model.getExhibitionManageId());
        Page<WorkOvertimeAudit> page = new Page<>();
        if (spaceCodeList == null || spaceCodeList.isEmpty()) {
            BeanUtil.copyProperties(pageParam, page);
            return page;
        }
        model.setSpaceCodeList(spaceCodeList);
        QueryWrapper<WorkOvertimeAudit> queryWrapper = createWorkOvertimeAuditQueryWrapper(model);
        return page(pageParam, queryWrapper);
    }

    @Override
    public List<WorkOvertimeAudit> listWorkOvertimeAudit(WorkOvertimeAuditDTO workOvertimeAuditDTO) {
        log.info("listWorkOvertimeAudit - 查询加班审核列表, workOvertimeAuditDTO={}", workOvertimeAuditDTO);
        QueryWrapper<WorkOvertimeAudit> queryWrapper = createWorkOvertimeAuditQueryWrapper(workOvertimeAuditDTO);
        return list(queryWrapper);
    }

    @Override
    public WorkOvertimeAuditVO getVOByWorkOvertimeNumber(String workOvertimeNumber) {
        log.info("getVOByWorkOvertimeNumber - 加班单号获取加班审核详情, workOvertimeNumber={}", workOvertimeNumber);
        WorkOvertimeAudit workOvertimeAudit = getByWorkOvertimeNumber(workOvertimeNumber);
        if (workOvertimeAudit == null) {
            return null;
        }
        return BeanUtil.toBean(workOvertimeAudit, WorkOvertimeAuditVO.class);
    }

    @Override
    public WorkOvertimeAudit getByWorkOvertimeNumber(String workOvertimeNumber) {
        QueryWrapper<WorkOvertimeAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(WorkOvertimeAudit::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(StrUtil.isNotBlank(workOvertimeNumber), WorkOvertimeAudit::getWorkOvertimeNumber, workOvertimeNumber);
        List<WorkOvertimeAudit> list = list(queryWrapper);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkOvertimeAudit saveWorkOvertimeAudit(WorkOvertimeAuditDTO workOvertimeAuditDTO) {
        log.info("saveWorkOvertimeAudit - 保存加班审核, workOvertimeAuditDTO={}", workOvertimeAuditDTO);
        WorkOvertimeAudit workOvertimeAudit = BeanUtil.toBean(workOvertimeAuditDTO, WorkOvertimeAudit.class);
        save(workOvertimeAudit);
        return workOvertimeAudit;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWorkOvertimeAudit(WorkOvertimeAuditDTO workOvertimeAuditDTO) {
        log.info("updateWorkOvertimeAudit - 更新加班审核, workOvertimeAuditDTO={}", workOvertimeAuditDTO);
        WorkOvertimeAudit workOvertimeAudit = BeanUtil.toBean(workOvertimeAuditDTO, WorkOvertimeAudit.class);
        return updateById(workOvertimeAudit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitWorkOvertimeAudit(WorkOvertimeAuditDTO workOvertimeAuditDTO) {
        log.info("submitWorkOvertimeAudit - 提交加班申请审核, workOvertimeAuditDTO={}", workOvertimeAuditDTO);
        WorkOvertimeAudit existWorkOvertime = getByWorkOvertimeNumber(workOvertimeAuditDTO.getWorkOvertimeNumber());
        if (existWorkOvertime != null && WorkOvertimeAuditAuditStatusEnum.APPROVED.eq(existWorkOvertime.getAuditStatus())) {
            throw BizException.wrap(HomeExceptionCode.WORK_OVERTIME_CAN_NOT_SUBMIT.getCode(), "加班申请已审核通过，不可再提交");
        }
        // 删除审核记录
        removeByWorkOvertimeNumber(workOvertimeAuditDTO.getWorkOvertimeNumber());
        // 保存审核记录
        WorkOvertimeAudit workOvertimeAudit = saveWorkOvertimeAudit(workOvertimeAuditDTO);
        // 发送加班申请的提醒站内信
        asyncSendSubmitInnerMsg(workOvertimeAudit);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditWorkOvertime(WorkOvertimeAuditDTO workOvertimeAuditDTO) {
        log.info("auditWorkOvertime - 审核加班申请, workOvertimeAuditDTO={}", workOvertimeAuditDTO);
        // 更新审核结果
        updateWorkOvertimeAuditStatus(workOvertimeAuditDTO);
        // 更新搭建商加班申请的审核结果
        CopyOptions copyOptions = CopyOptions
                .create()
                .setIgnoreProperties(CommonConstants.COMMON_IGNORE_PROPERTIES);
        WorkOvertimeDTO workOvertimeDTO = BeanUtil.toBean(workOvertimeAuditDTO, WorkOvertimeDTO.class, copyOptions);
        return homeWorkOvertimeService.auditWorkOvertime(workOvertimeDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkOvertimeAudit updateWorkOvertimeAuditStatus(WorkOvertimeAuditDTO workOvertimeAuditDTO) {
        log.info("updateWorkOvertimeAuditStatus - 更新加班审核结果, workOvertimeAuditDTO={}", workOvertimeAuditDTO);
        WorkOvertimeAudit workOvertimeAudit = getByWorkOvertimeNumber(workOvertimeAuditDTO.getWorkOvertimeNumber());
        if (workOvertimeAudit == null) {
            throw BizException.wrap(HomeExceptionCode.WORK_OVERTIME_AUDIT_NOT_EXIST);
        }
        if (!WorkOvertimeAuditAuditStatusEnum.SUBMIT.eq(workOvertimeAudit.getAuditStatus())) {
            throw BizException.wrap(HomeExceptionCode.WORK_OVERTIME_CAN_NOT_AUDIT.getCode(), "审核失败，加班申请已取消或已审核");
        }
        // 更新审核结果
        workOvertimeAudit.setAuditStatus(workOvertimeAuditDTO.getAuditStatus());
        workOvertimeAudit.setAuditOpinion(workOvertimeAuditDTO.getAuditOpinion());
        workOvertimeAudit.setAuditTime(LocalDateTime.now());
        workOvertimeAudit.setAuditUserId(workOvertimeAuditDTO.getAuditUserId());
        workOvertimeAudit.setAuditUserName(workOvertimeAuditDTO.getAuditUserName());
        workOvertimeAudit.setHomeCourtId(workOvertimeAuditDTO.getHomeCourtId());
        workOvertimeAudit.setHomeCountName(workOvertimeAuditDTO.getHomeCountName());
        updateById(workOvertimeAudit);
        return workOvertimeAudit;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelWorkOvertimeAudit(String workOvertimeNumber) {
        log.info("cancelWorkOvertimeAudit - 取消加班申请审核, workOvertimeNumber={}", workOvertimeNumber);
        return removeByWorkOvertimeNumber(workOvertimeNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByWorkOvertimeNumber(String workOvertimeNumber) {
        log.info("removeByWorkOvertimeNumber - 加班单号删除加班审核, workOvertimeNumber={}", workOvertimeNumber);
        WorkOvertimeAudit workOvertimeAudit = getByWorkOvertimeNumber(workOvertimeNumber);
        if (workOvertimeAudit == null) {
            return true;
        }
        List<WorkOvertimeAudit> list = new ArrayList<>();
        list.add(workOvertimeAudit);
        return removeByIdsOfLogic(list);
    }

    @Override
    public boolean sendSubmitInnerMsg(WorkOvertimeAudit workOvertimeAudit) {
        log.info("sendSubmitInnerMsg - 发送加班申请站内信提醒, workOvertime={}", workOvertimeAudit);

        String workOvertimeType = workOvertimeAudit.getWorkOvertimeType();
        String workOvertimeTypeValue = "加班申请";
        if (StrUtil.isNotBlank(workOvertimeType)) {
            if (WorkOvertimeWorkOvertimeTypeEnum.WORK_OVERTIME_TYPE.getCode().equals(workOvertimeType)) {
                workOvertimeTypeValue = "加班申请";
            } else if (WorkOvertimeWorkOvertimeTypeEnum.ADVANCE_APPROACH.getCode().equals(workOvertimeType)) {
                workOvertimeTypeValue = "提前入场申请";
            } else if (WorkOvertimeWorkOvertimeTypeEnum.LOAD_UPLOAD_SERVICE.getCode().equals(workOvertimeType)) {
                workOvertimeTypeValue = "装卸服务申请";
            }
        }
        String content = String.format(BusinessInnerMsgTemplate.WORK_OVERTIME_SUBMIT_TEMPLATE,
                workOvertimeAudit.getExhibitionManageName(), workOvertimeTypeValue, workOvertimeAudit.getWorkOvertimeNumber(), workOvertimeAudit.getCompanyName(), workOvertimeTypeValue);
        // 查询负责该展会展厅负责处理加班申请的主场
        String spaceCode = workOvertimeAudit.getSpaceCode();
        if (StrUtil.isBlank(spaceCode)) {
            log.info("sendSubmitInnerMsg - 找不到展厅，无法发送消息");
            return false;
        }
        List<String> spaceCodeList = new ArrayList<>();
        spaceCodeList.add(spaceCode);
        List<ServiceProviderVO> serviceProviderList
                = homeServiceProviderService.listServiceProvidersByExhibitionId(workOvertimeAudit.getExhibitionManageId(), spaceCodeList, ServiceProviderTypeEnum.HOME_SERVICE_PROVIDER.getCode());
        if (serviceProviderList == null || serviceProviderList.isEmpty()) {
            log.info("sendSubmitInnerMsg - 找不到主场，无法发送消息");
            return false;
        }
        for (ServiceProviderVO serviceProviderVO : serviceProviderList) {
            sendMsgUtil.sendInnerMsgByTeamId(content, serviceProviderVO.getId(), StaticContextUtil.getProjectSystemScene());
        }
        return true;
    }

    @Override
    public void asyncSendSubmitInnerMsg(WorkOvertimeAudit workOvertimeAudit) {
        threadPoolTaskExecutor.execute(() -> sendSubmitInnerMsg(workOvertimeAudit));
    }

    /**
     * 创建查询WorkOvertimeAudit的QueryWrapper.
     *
     * @param param WorkOvertimeAuditDTO.
     * @return QueryWrapper.
     */
    private QueryWrapper<WorkOvertimeAudit> createWorkOvertimeAuditQueryWrapper(WorkOvertimeAuditDTO param) {
        QueryWrapper<WorkOvertimeAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(WorkOvertimeAudit::getIsDeleted, BusinessConstant.DELETE_NO)
                .like(StrUtil.isNotBlank(param.getWorkOvertimeNumber()),
                        WorkOvertimeAudit::getWorkOvertimeNumber, param.getWorkOvertimeNumber())
                .eq(StrUtil.isNotBlank(param.getWorkOvertimeType()), WorkOvertimeAudit::getWorkOvertimeType, param.getWorkOvertimeType())
                .eq(param.getExhibitionManageId() != null, WorkOvertimeAudit::getExhibitionManageId, param.getExhibitionManageId())
                .like(StrUtil.isNotBlank(param.getSpaceName()), WorkOvertimeAudit::getSpaceName, param.getSpaceName())
                .like(StrUtil.isNotBlank(param.getSiteName()), WorkOvertimeAudit::getSiteName, param.getSiteName())
                .like(StrUtil.isNotBlank(param.getCompanyName()), WorkOvertimeAudit::getCompanyName, param.getCompanyName())
                .eq(param.getAuditStatus() != null, WorkOvertimeAudit::getAuditStatus, param.getAuditStatus())
                .eq(param.getOvertimeDate() != null, WorkOvertimeAudit::getOvertimeDate, param.getOvertimeDate())
                .eq(StrUtil.isNotBlank(param.getSpaceCode()), WorkOvertimeAudit::getSpaceCode, param.getSpaceCode())
                .in(param.getSpaceCodeList() != null && param.getSpaceCodeList().isEmpty(), WorkOvertimeAudit::getSpaceCode, param.getSpaceCodeList())
        ;
        return queryWrapper;
    }
}
